/*
 动画
  定义几个关键信息：
  1.插值器，起始值、结束值，Tween(begin: xxx, end: xxx)
  2.时间:Duration()
  3.变化过程:Curves
  4.如何执行，顺序、倒序、组合等等, 比如:
  controller.forwad()
  repeat()
  reverse()

  开发步骤：
  1.继承 TickerProvider ，如果有多个AnimationController，则应该使用 TickerProviderStateMixin,
  一般一个control就够用了,推荐使用 SingleTickerProviderStateMixin
  2.定义动画
  3.监听动画的改变，刷新界面
  4.执行
  5.释放动画资源

  场景：
  1.路由动画，参考17节，路由
  2.Hero动画，即共享元素动画
  3.网格或列表中添加或删除元素时应用动画

  动画内部实现原理:
  Ticker 配合 setState()
  每次回调都刷新界面
  
 */

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      appBar: AppBar(
        title: Text('动画'),
      ),
      body: AnimationImage(),
    ),
  ));
}

class AnimationImage extends StatefulWidget {
  @override
  _AnimationImageState createState() => _AnimationImageState();
}

class _AnimationImageState extends State<AnimationImage>
    with TickerProviderStateMixin {
  // 可以定义多个animation，
  late Animation<double> animation;
  late AnimationController controller;

  @override
  Widget build(BuildContext context) {
    // 还可以再封装以下控件，将Image和animation作为参数，封装宽高的变化
    // Flutter中正是通过这种方式封装了很多动画，如：FadeTransition、ScaleTransition、SizeTransition等，很多时候都可以复用这些预置的过渡类。
    return AnimatedBuilder(
        animation: animation,
        builder: (BuildContext ctx, Widget? child) {
          return Center(
            child: Container(
              width: animation.value,
              height: animation.value,
              child: child,
            ),
          );
        },
        // 这里的child用来传递给回调函数,不会重新绘制,提高效率
        child: Image.asset("assets/mg.jpg"));
  }

  @override
  void initState() {
    super.initState();
    // 定义控制器，包含时间
    controller =
        AnimationController(duration: const Duration(seconds: 3), vsync: this);
    // 使用插值器，可以使用线性和非线性
    animation = CurvedAnimation(parent: controller, curve: Curves.easeInQuad);
    // 表示前50%的动画时间，创建其他的动画也可以指定时间，共享同一个Controller
    // animation = CurvedAnimation(parent: controller, curve: Interval(0.0, 0.5, curve: Curves.linear));
    // 定义起始和结束
    animation = Tween(begin: 0.0, end: 300.0)
        // 串联动画,可以串联多个动画和时间段
        .chain(CurveTween(curve: Curves.bounceOut))
        // 指定时间段
        .chain(CurveTween(curve: Interval(0.5, 1)))
        .animate(controller);
    // 监听每一帧的变化，改变状态
    // 如果使用AnimatedBuilder则不需要监听
    // controller.addListener(() {
    //   setState(() {});
    // });

    // 监听动画
    animation.addStatusListener((status) {
      if (status == AnimationStatus.forward) {
        // 动画正在正向执行
      } else if (status == AnimationStatus.reverse) {
        // 动画正在反向执行
      } else if (status == AnimationStatus.completed) {
        // 动画在终点停止
      } else if (status == AnimationStatus.dismissed) {
        // 动画在起始点停止
      }
    });
    // 启动
    controller.forward();

    // controller.reverse(); // 反向执行
    // controller.repeat(); // 反向执行
  }

  @override
  void dispose() {
    // 释放动画资源
    controller.dispose();
    super.dispose();
  }
}
